home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1996 January / macformat-033.iso / mac / Shareware City / Graphics / GifScan 1.6 / Sources / Lib Sources / DSUserProcs.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-10-09  |  18.2 KB  |  653 lines  |  [TEXT/MMCC]

  1. /******************************************************************************
  2. **
  3. **  Project Name:    DropShell
  4. **     File Name:    DSUserProcs.c
  5. **
  6. **   Description:    Specific AppleEvent handlers used by the DropBox
  7. **
  8. *******************************************************************************
  9. **                       A U T H O R   I D E N T I T Y
  10. *******************************************************************************
  11. **
  12. **    Initials    Name
  13. **    --------    -----------------------------------------------
  14. **    LDR            Leonard Rosenthol
  15. **    MTC            Marshall Clow
  16. **    SCS            Stephan Somogyi
  17. **
  18. *******************************************************************************
  19. **                      R E V I S I O N   H I S T O R Y
  20. *******************************************************************************
  21. **
  22. **      Date        Time    Author    Description
  23. **    --------    -----    ------    ---------------------------------------------
  24. **    06/23/94            LDR        Added support for ProcessItem and ProcessFolder handling
  25. **    02/20/94            LDR        Modified Preflight & Postflight to take item count
  26. **    01/25/92            LDR        Removed the use of const on the userDataHandle
  27. **    12/09/91            LDR        Added the new SelectFile userProc
  28. **                                Added the new Install & DisposeUserGlobals procs
  29. **                                Modified PostFlight to only autoquit on odoc, not pdoc
  30. **    11/24/91            LDR        Added the userProcs for pdoc handler
  31. **                                Cleaned up the placement of braces
  32. **                                Added the passing of a userDataHandle
  33. **    10/29/91            SCS        Changes for THINK C 5
  34. **    10/28/91            LDR        Officially renamed DropShell (from QuickShell)
  35. **                                Added a bunch of comments for clarification
  36. **    10/06/91    00:02    MTC        Converted to MPW C
  37. **    04/09/91    00:02    LDR        Added to Projector
  38. **
  39. ******************************************************************************/
  40.  
  41. /******************************************************************************
  42. **
  43. **    DropUnix history:    KRB = Kevin R. Boyce, RWD = Ryan Davis
  44. **
  45. **    04/21/95        KRB        Added conditional compilation for Think C (Universal headers,
  46. **                             but old ANSI/console library).
  47. **    04/??/95        RWD        First release.
  48. **
  49. ********************************************************************************/
  50.  
  51. #include "GifScan.h"
  52.  
  53. #include <Files.h>
  54. #include <StandardFile.h>
  55.  
  56. #include <stdlib.h>            // For malloc & free 
  57. #include <string.h>            // For strcpy 
  58. #include <stdio.h>
  59.  
  60. #include "DSGlobals.h"
  61. #include "DSUserProcs.h"
  62. #include "Prefs.h"
  63.  
  64. extern thePrefsHandle        gPrefs;
  65.  
  66. WindowRef        gOutWindow;
  67.  
  68. #define ValidatePtr(ptr) \
  69.     if (!ptr) {\
  70.         printf("Error allocating memory! Error #%d\n", MemError() );\
  71.         exit(-1);\
  72.     }
  73.  
  74. // User Structs 
  75.     typedef struct {
  76.         unsigned int count;
  77.         char ** names;
  78.     } fileNameList, *fileNamePtr, **fileNameHandle;
  79.  
  80. // Static Prototypes 
  81.     static OSErr ProcessFolder(FSSpecPtr myFSSPtr, Handle userDataHandle);
  82.     static OSErr ProcessItem(FSSpecPtr myFSSPtr, Handle userDataHandle);
  83.     static void SetApplicationName(Handle userDataHandle);
  84.     static void AllocateAppNames(Handle *userDataHandle, unsigned long numOfFiles);
  85.     static void DeallocateAppNames(Handle userDataHandle);
  86.  
  87. /*
  88.     This routine is called during init time.
  89.     
  90.     It allows you to install more AEVT Handlers beyond the standard four
  91. */
  92.  
  93. pascal void InstallOtherEvents (void) {
  94. }
  95.  
  96.  
  97. /*    
  98.     This routine is called when an OAPP event is received.
  99.     
  100.     Currently, all it does is set the gOApped flag, so you know that
  101.     you were called initally with no docs, and therefore you shouldn't 
  102.     quit when done processing any following odocs.
  103. */
  104.  
  105. pascal void OpenApp (void) 
  106. {
  107.     gOApped = true;
  108. }
  109.  
  110.  
  111. /*    
  112.     This routine is called when an QUIT event is received.
  113.     
  114.     We simply set the global done flag so that the main event loop can
  115.     gracefully exit.  We DO NOT call ExitToShell for two reasons:
  116.     1) It is a pretty ugly thing to do, but more importantly
  117.     2) The Apple event manager will get REAL upset!
  118. */
  119.  
  120. pascal void QuitApp (void) 
  121. {
  122.     gDone = true;    //    All Done! 
  123. }
  124.  
  125.  
  126. /*    
  127.     This routine is the first one called when an ODOC or PDOC event is received.
  128.     
  129.     In this routine you would place code used to setup structures, etc. 
  130.     which would be used in a 'for all docs' situation (like "Archive all
  131.     dropped files")
  132.  
  133.     Obviously, the opening boolean tells you whether you should be opening
  134.     or printing these files based on the type of event recieved.
  135.     
  136.     NEW IN 2.0!
  137.     The itemCount parameter is simply the number of items that were dropped on
  138.     the application and that you will be processing.  This gives you the ability
  139.     to do a single preflight for memory allocation needs, rather than doing it
  140.     once for each item as in previous versions.
  141.     
  142.     userDataHandle is a handle that you can create & use to store your own
  143.     data structs.  This dataHandle will be passed around to the other 
  144.     odoc/pdoc routines so that you can get at your data without using
  145.     globals - just like the new StandardFile.  
  146.     
  147.     We also return a boolean to tell the caller if you support this type
  148.     of event.  By default, our dropboxes don't support the pdoc, so when
  149.     opening is FALSE, we return FALSE to let the caller send back the
  150.     proper error code to the AEManager.
  151. */
  152.  
  153. pascal Boolean PreFlightDocs (Boolean opening, short itemCount, Handle *userDataHandle) 
  154. {
  155.     if ((opening) && (itemCount > 0)) 
  156.     {    // Don't support printing, so don't waste our time 
  157.  
  158.         /*
  159.         ** The following is a bug, it is the responsibility of ProcessItem to increment g_argc
  160.         ** g_argc += itemCount;
  161.         */
  162.  
  163.         AllocateAppNames(userDataHandle, itemCount);
  164.         SetApplicationName(*userDataHandle);
  165.     }
  166.  
  167.     return opening;        // we support opening, but not printing - see above
  168. }
  169.  
  170. /*    
  171.     This routine is called for each file passed in the ODOC event.
  172.     
  173.     In this routine you would place code for processing each file/folder/disk that
  174.     was dropped on top of you.
  175. */
  176.  
  177. pascal void OpenDoc ( FSSpecPtr myFSSPtr, Boolean opening, Handle userDataHandle ) {
  178.  
  179.     OSErr    err = noErr;
  180.     
  181.     #ifdef qWalkFolders
  182.         /*
  183.             For this case we need to determine if the FSSpec is a file or folder.
  184.             If it's a folder, we then need to process each item in that folder,
  185.             otherwise just process the item.
  186.         */
  187.         if (FSpIsFolder(myFSSPtr))
  188.             err = ProcessFolder(myFSSPtr, userDataHandle);
  189.         else
  190.             err = ProcessItem(myFSSPtr, userDataHandle);
  191.     #else
  192.         /*
  193.             For this case we just call ProcessItem on the FSSpec above.
  194.         */
  195.         err = ProcessItem(myFSSPtr, userDataHandle);
  196.     #endif
  197.     
  198.     if ( err != noErr ) ErrorAlert(kErrStringID, 9, 12931, true);
  199.     // you should probably do something if you get back an error ;)
  200. }
  201.  
  202.  
  203. /*    
  204.     This routine is the last routine called as part of an ODOC event.
  205.     
  206.     In this routine you would place code to process any structures, etc. 
  207.     that you setup in the PreflightDocs routine.
  208.  
  209.     NEW IN 2.0!
  210.     The itemCount parameter was the number of items that you processed.
  211.     It is passed here just in case you need it ;)  
  212.     
  213.     If you created a userDataHandle in the PreFlightDocs routines, this is
  214.     the place to dispose of it since the Shell will NOT do it for you!
  215. */
  216.  
  217. pascal void PostFlightDocs ( Boolean opening, short itemCount, Handle userDataHandle ) {
  218.  
  219.     int argc;
  220.     char ** argv;
  221.     fileNamePtr fileNames;
  222.     
  223.     extern int UnixMain(int argc, char **argv);
  224.  
  225.     /*
  226.     ** OK, this is IT! We have finally processed all the files, now we send the
  227.     ** pathnames & count off to the REAL unix function...
  228.     */
  229.     
  230.     HLock(userDataHandle);
  231.     
  232.     fileNames = *((fileNameHandle) userDataHandle);
  233.     argc = fileNames->count;
  234.     argv = fileNames->names;
  235.  
  236.     UnixMain(argc, argv);
  237.     
  238.     HUnlock(userDataHandle);
  239.     /*
  240.     ** Now deallocate the memory stored by PreFlightDocs
  241.     */
  242.     
  243.     DeallocateAppNames(userDataHandle);
  244. }
  245.  
  246. /*
  247.     This routine gets called for any folder (or disk) that the caller wants 
  248.     processed as a set of component items, instead of as a single entity.
  249.     The determining factor is the definition of the qWalkFolder compiler directive.
  250. */
  251. static OSErr ProcessFolder(FSSpecPtr myFSSPtr, Handle userDataHandle)
  252. {
  253.     OSErr        err = noErr;
  254.     short        index, oldIndex, localIndex;
  255.     FSSpec        localFSSpec, curFSSpec;
  256.     CInfoPBRec    cipb;
  257.     Str255        fName, vFName;
  258.     long        dirID, origDirID;
  259.     Boolean        foundPosition;
  260.  
  261.      // copy the source locally to avoid recursion problems
  262.      BlockMoveData(myFSSPtr, &localFSSpec, sizeof(FSSpec));
  263.      
  264.     //    get the dirID for THIS folder, not it's parent!
  265.     BlockMoveData(localFSSpec.name, fName, 32);
  266.     
  267.     cipb.hFileInfo.ioCompletion    = 0L;
  268.     cipb.hFileInfo.ioNamePtr    = fName;
  269.     cipb.hFileInfo.ioVRefNum    = localFSSpec.vRefNum;
  270.     cipb.hFileInfo.ioFDirIndex    = 0;    // use the dir & vRefNum;
  271.     cipb.hFileInfo.ioDirID        = localFSSpec.parID;
  272.     err = PBGetCatInfoSync(&cipb);
  273.     
  274.     if (!err) {        
  275.         origDirID = cipb.dirInfo.ioDrDirID; // copy the sucker
  276.         index = 1;
  277.                 
  278.         // index through all contents of this folder
  279.         while (err == noErr) {
  280.             dirID = origDirID;
  281.             localIndex = index;
  282.             fName [0] = 0;
  283.             cipb.hFileInfo.ioCompletion    = 0L;
  284.             cipb.hFileInfo.ioNamePtr    = fName;
  285.             cipb.hFileInfo.ioVRefNum    = localFSSpec.vRefNum;
  286.             cipb.hFileInfo.ioFDirIndex    = localIndex;    // use a real index
  287.             cipb.hFileInfo.ioDirID        = dirID;
  288.             err = PBGetCatInfoSync(&cipb);
  289.  
  290.             if (!err) {
  291.                 BlockMoveData(fName, curFSSpec.name, 32);
  292.                 curFSSpec.vRefNum    = cipb.hFileInfo.ioVRefNum;
  293.                 curFSSpec.parID        = dirID;
  294.             
  295.                 /*    
  296.                     Check to see if this entry is a folder.
  297.                 */
  298.                 if (cipb.hFileInfo.ioFlAttrib & ioDirMask) {
  299.                     err = ProcessFolder(&curFSSpec, userDataHandle);
  300.                  } else
  301.                     err = ProcessItem(&curFSSpec, userDataHandle);
  302.             
  303.                 //    If we've had an error, get out! 
  304.                 if (err)    break;
  305.  
  306.                 // dirID = origDirID;    
  307.                 localIndex = index;    
  308.  
  309.                 /*    
  310.                     Now take into account new files being created
  311.                     in the current directory & messing up our index.
  312.                     See Dev.CD Vol. XI:Tools & Apps (Moof!):Misc Utilities:
  313.                     Disinfectant & Source 2.5.1:Sample:Notes:Scan Alg    
  314.                 */
  315.                 vFName [0] = 0;
  316.                 cipb.hFileInfo.ioCompletion    = 0L;
  317.                 cipb.hFileInfo.ioNamePtr    = vFName;
  318.                 cipb.hFileInfo.ioVRefNum    = localFSSpec.vRefNum;
  319.                 cipb.hFileInfo.ioFDirIndex    = localIndex;    // use a real index
  320.                 cipb.hFileInfo.ioDirID        = dirID;
  321.                 err = PBGetCatInfoSync(&cipb);
  322.                 oldIndex = index;
  323.                 if (!err) {
  324.                     //    If they're equal - same place, go to next 
  325.                     if (EqualString (vFName, fName, false, false))
  326.                         index++;
  327.                 }
  328.                 
  329.                 //    If we didn't advance, then perhaps a file was created or deleted 
  330.                 if (oldIndex == index) {
  331.                     oldIndex        = index;    // save off the old 
  332.                     index            = 0;        // and start at the beginning 
  333.                     err                = noErr;
  334.                     vFName [0]        = 0;
  335.                     foundPosition    = false;
  336.                     
  337.                     while (!foundPosition) {
  338.                         index++;
  339.                         vFName [0] = 0;
  340.                         cipb.hFileInfo.ioCompletion    = 0L;
  341.                         cipb.hFileInfo.ioNamePtr    = vFName;
  342.                         cipb.hFileInfo.ioVRefNum    = localFSSpec.vRefNum;
  343.                         cipb.hFileInfo.ioFDirIndex    = index;    // now use a real index 
  344.                         cipb.hFileInfo.ioDirID        = dirID;
  345.                         err = PBGetCatInfoSync(&cipb);
  346.                         
  347.                         if (err == fnfErr) {  // we've just been deleted
  348.                             index = oldIndex;
  349.                             foundPosition = true;
  350.                             err = noErr;    // have to remember to reset this!
  351.                         }
  352.                         
  353.                     //    found same file & same index position 
  354.                     //    so try the next item 
  355.                         if ((!foundPosition) && EqualString(fName, vFName, false, false)) {
  356.                             index++;
  357.                             foundPosition = true;
  358.                         }
  359.                     }
  360.                 }
  361.             }
  362.         }
  363.     }
  364.     
  365.     return(err);
  366. }
  367.  
  368. /*
  369.     This routine is called when the user chooses "Select File…" from the
  370.     File Menu.
  371.     
  372.     Currently it simply calls the new StandardGetFile routine to have the
  373.     user select a single file (any type, numTypes = -1) and then calls the
  374.     SendODOCToSelf routine in order to process it.  
  375.             
  376.     The reason we send an odoc to ourselves is two fold: 1) it keeps the code
  377.     cleaner as all file openings go through the same process, and 2) if events
  378.     are ever recordable, the right things happen (this is called Factoring!)
  379.  
  380.     Modification of this routine to only select certain types of files, selection
  381.     of multiple files, and/or handling of folder & disk selection is left 
  382.     as an exercise to the reader.
  383. */
  384. pascal void SelectFile (void)
  385. {
  386.     StandardFileReply    stdReply;
  387.     SFTypeList            theTypeList;
  388.  
  389.     StandardGetFile(nil, -1, theTypeList, &stdReply);
  390.     if (stdReply.sfGood)    // user did not cancel
  391.         SendODOCToSelf(&stdReply.sfFile);    // so send me an event!
  392. }
  393.  
  394. /*
  395.     This routine is called during the program's initialization and gives you
  396.     a chance to allocate or initialize any of your own globals that your
  397.     dropbox needs.
  398.     
  399.     You return a boolean value which determines if you were successful.
  400.     Returning false will cause DropShell to exit immediately.
  401. */
  402.  
  403. pascal Boolean InitUserGlobals(void)
  404. {
  405.     // Get the Preferences 
  406.     gPrefs = (thePrefsHandle)NewHandle(sizeof(thePrefs));
  407.     if ( gPrefs )
  408.     {
  409.         gPrefs = (thePrefsHandle)ReadPrefData();
  410.         MoveHHi((Handle)gPrefs);
  411.     }
  412.     else
  413.     {
  414.         ErrorAlert(kErrStringID, eCouldntGetToPrefs, 12900, false);
  415.     }    
  416.     
  417.     if ( !DoNew() )
  418.         return (false);
  419.     
  420.     return(true);
  421. }
  422.  
  423. /*
  424.     This routine is called during the program's cleanup and gives you
  425.     a chance to deallocate any of your own globals that you allocated 
  426.     in the above routine.
  427. */
  428. pascal void DisposeUserGlobals(void)
  429. {
  430.     (*gPrefs)->winRect = gOutWindow->portRect;
  431.     LocalToGlobal(&topLeft((*gPrefs)->winRect));
  432.     LocalToGlobal(&botRight((*gPrefs)->winRect));
  433.     
  434.     if ( (*gPrefs)->promptSave ) HandleTextFileSave();
  435.         
  436.     if ( gOutWindow != nil ) DoCloseWindow(gOutWindow);
  437.     
  438.     if ( !WritePrefData((Handle)gPrefs) )
  439.         ErrorAlert(kErrStringID, eCouldNotWriteResources, 12900, false);
  440. }
  441.  
  442. long GetFullPath (FSSpec *fsspec, char *path, OSErr *err);
  443. unsigned short ReverseCopyP2CStr (unsigned char *pas, char *c);
  444. void ReverseCStr (char *str);
  445.  
  446. /*
  447.     This routine gets called for each item (which could be either a file or a folder)
  448.     that the caller wants dropped.  The determining factor is the definition of the 
  449.     qWalkFolder compiler directive.   Either way, the item in question should be
  450.     processed as a single item and not "dissected" into component units (like subfiles
  451.     of a folder!)
  452. */
  453. OSErr ProcessItem(FSSpecPtr myFSSPtr, Handle userDataHandle)
  454. {
  455.     char    path[1000];
  456.     OSErr    err = noErr;
  457.     unsigned long    len;    
  458.     
  459.     len = GetFullPath (myFSSPtr, path, &err);
  460.     if (err != noErr) return err;
  461.  
  462.     if (path != nil) 
  463.     {
  464.         fileNamePtr fileNames;
  465.         
  466.         HLock(userDataHandle);
  467.             fileNames = *((fileNameHandle) userDataHandle);
  468.             
  469.             fileNames->names[(fileNames->count)] = (char *) NewPtr((len+1) * sizeof(char));
  470.             ValidatePtr(fileNames->names[(fileNames->count)]);
  471.     
  472.             strcpy(fileNames->names[(fileNames->count)], path);
  473.             (fileNames->count)++;
  474.         HUnlock(userDataHandle);
  475.     }
  476.  
  477.     return(err);
  478. }
  479.  
  480. long GetFullPath (FSSpec *fsspec, char *path, OSErr *err)
  481. {
  482.     short        volume = fsspec->vRefNum;
  483.     OSErr        fsErr = noErr;
  484.     CInfoPBRec    catinfo;
  485.     char            dirName[64];
  486.     long            retLen = 0L, len;
  487.     register char    *p = path;
  488.     
  489.     // All comments assume a  file whose full path is
  490.     //    HD:Fonts:Garamond
  491.     
  492.     // If fsspec doesn't designate a file (i.e., it's a volume or directory), we write a colon
  493.     if ( FSpIsFolder (fsspec)) 
  494.     {
  495.         *p++ = ':';
  496.         retLen++;
  497.     }
  498.     
  499.     // First, copy the file name backwards from a Pascal to a C string:
  500.     //    "\pGaramond"  becomes "dnomaraG"
  501.  
  502.     len = (long) ReverseCopyP2CStr (fsspec->name, p);
  503.     p += len;
  504.     retLen += len;
  505.     
  506.     // Yea, I know this is cheap, but it is used ONCE AND it makes it clearer {RWD} 
  507.     
  508.     #define FSpIsVolume(FSSpec) ((FSSpec)->parID == fsRtParID)
  509.     
  510.     if ( ! FSpIsVolume (fsspec)) 
  511.     {        // Don't do anything more if we've got a volume
  512.         catinfo.dirInfo.ioVRefNum = volume;
  513.         catinfo.dirInfo.ioNamePtr = (StringPtr) dirName;
  514.         catinfo.dirInfo.ioDrParID = fsspec->parID;
  515.         
  516.         // Now copy the rest of the path, one level at a time, backwards:
  517.         //    "dnomaraG:stnoF:DH"
  518.         do 
  519.         {
  520.             catinfo.dirInfo.ioFDirIndex = -1;
  521.             catinfo.dirInfo.ioDrDirID = catinfo.dirInfo.ioDrParID;    // <= This is the key — go from the
  522.                                                         //    current folder to its parent
  523.             fsErr = PBGetCatInfoSync (&catinfo);
  524.             if (fsErr == noErr) 
  525.             {
  526.                 *p++ = ':';
  527.                 retLen += 1 + (len = ReverseCopyP2CStr ((StringPtr) dirName, p));
  528.                 p += len;
  529.             }
  530.             else 
  531.             {
  532.                 *err = fsErr;
  533.                 return retLen;
  534.             }
  535.         } while (catinfo.dirInfo.ioDrDirID != fsRtDirID);
  536.     }
  537.     
  538.     // Finally, reverse the string and return its length and any error that might have occurred (ReverseCopyP2CStr has
  539.     //    already appended a nil character, so we don't have to worry about it here)
  540.     ReverseCStr (path);
  541.     *err = fsErr;
  542.     return retLen;
  543. }
  544.  
  545. unsigned short ReverseCopyP2CStr (register unsigned char *pas, register char *c)
  546. {
  547.     register short    i, len = *pas++;
  548.     
  549.     for (i = len, c += len; i > 0; i--)
  550.         *--c = *pas++;
  551.     c += len;
  552.     *c = '\0';
  553.     return len;
  554. }
  555.  
  556. void ReverseCStr (register char *str)
  557. {
  558.     register short        n = 0L, i;
  559.     register char        t, *p1, *p2;
  560.     
  561.     p1 = p2 = str;
  562.     while (*p2++)
  563.         ;
  564.     p2--;
  565.     n = (p2 - p1) / 2;
  566.     for (i = n; i > 0; i--) {
  567.         t = *--p2;
  568.         *p2 = *p1;
  569.         *p1++ = t;
  570.     }
  571. }
  572.  
  573. static void SetApplicationName(Handle userDataHandle) 
  574. {
  575.     Str255         appName;
  576.     fileNamePtr fileNames;
  577.     
  578.     GetMyAppName(appName);
  579.     
  580.     HLock(userDataHandle);
  581.     
  582.     fileNames = *((fileNameHandle) userDataHandle);
  583.     if ( fileNames->names[0] == nil) 
  584.     {
  585.         fileNames->names[0] = (char *) NewPtr(**fileNames->names + 1); // pstr's size in byte 0 
  586.         
  587.         if (fileNames->names[0] == nil || MemError()) 
  588.             ErrorAlert(kErrStringID, eMemError, MemError(), true);
  589.         
  590.         strcpy(fileNames->names[0], p2cstr(appName));
  591.     }
  592.     
  593.     HUnlock(userDataHandle);
  594. }
  595.  
  596. static void AllocateAppNames(Handle *userDataHandle, unsigned long numOfFiles) 
  597. {
  598.     fileNameHandle             fileNameHdl;
  599.     fileNamePtr             fileNames;
  600.     static unsigned char    *someChars;
  601.     
  602.     fileNameHdl = (fileNameHandle) NewHandleClear(sizeof(fileNameList));
  603.     if (!fileNameHdl || MemError() ) 
  604.         ErrorAlert(kErrStringID, eMemError, MemError(), true);
  605.     
  606.     HLock((Handle) fileNameHdl);
  607.     
  608.     fileNames = *fileNameHdl;
  609.     
  610.     fileNames->count = 1; // we count one right off for the app name 
  611.     fileNames->names = (char **) NewPtrClear((numOfFiles + 1) * sizeof(char *));
  612.     if (fileNames->names == nil) 
  613.         ErrorAlert(kErrStringID, eMemError, MemError(), true);
  614.         
  615.     fileNames = nil;
  616.     
  617.     HUnlock((Handle) fileNameHdl);
  618.     
  619.     *userDataHandle = (Handle) fileNameHdl;
  620. }
  621.  
  622. static void DeallocateAppNames(Handle userDataHandle) 
  623. {
  624.     fileNamePtr     fileNames;
  625.     unsigned int     index;
  626.     
  627.     HLock(userDataHandle);
  628.     
  629.     fileNames = *((fileNameHandle) userDataHandle);
  630.     
  631.     for (index = 0; index < fileNames->count; index++)
  632.     {
  633.         if (fileNames->names[index] != nil)
  634.         {
  635.             DisposePtr(fileNames->names[index]);
  636.             if (MemError()) 
  637.                 ErrorAlert(kErrStringID, eMemError, MemError(), true);
  638.             fileNames->names[index] = nil;
  639.         }
  640.     }
  641.     
  642.     DisposePtr((Ptr) fileNames->names);
  643.     if ( MemError() )  ErrorAlert(kErrStringID, eMemError, MemError(), true);
  644.     
  645.     fileNames = nil;
  646.         
  647.     HUnlock(userDataHandle);
  648.     
  649.     DisposeHandle(userDataHandle);
  650.     if ( MemError() ) 
  651.         ErrorAlert(kErrStringID, eMemError, MemError(), true);
  652. }
  653.